SPB Git

spb/autoscholar

Public
1.5 KB · 44 lines tsx
1"use client";2import { useRouter } from "next/navigation";3import { type FormEvent, useState } from "react";4import { useToast } from "@/components/Toast";5import { type ApiError, api } from "@/lib/client/api";67export function OverrideForm({ runId, gates }: { runId: string; gates: string[] }) {8  const router = useRouter();9  const toast = useToast();10  const [busy, setBusy] = useState(false);11  return (12    <form13      className="mt-2 space-y-2"14      onSubmit={async (e: FormEvent<HTMLFormElement>) => {15        e.preventDefault();16        setBusy(true);17        try {18          await api(`/api/admin/quality/${runId}/override`, {19            json: { rationale: new FormData(e.currentTarget).get("rationale") },20          });21          toast.push("success", "Override recorded; run now awaits explicit publication.");22          router.refresh();23        } catch (err) {24          toast.push("error", (err as ApiError).message);25        } finally {26          setBusy(false);27        }28      }}29    >30      <p className="muted text-sm">31        Overriding: <code className="text-xs">{gates.join(", ")}</code>. The rationale is permanently recorded32        in the audit log and the publication decision.33      </p>34      <label htmlFor="rationale" className="label">35        Rationale (min 20 characters)36      </label>37      <textarea id="rationale" name="rationale" required minLength={20} rows={3} className="input" />38      <button type="submit" className="btn btn-danger" disabled={busy}>39        Record override40      </button>41    </form>42  );43}44
Files · main
Menu

Theme